package com.example.tt.mqtt;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.TaskStackBuilder;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.NotificationCompat;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.ToggleButton;

import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.BlockingConnection;
import org.fusesource.mqtt.client.Callback;
import org.fusesource.mqtt.client.CallbackConnection;
import org.fusesource.mqtt.client.Listener;
import org.fusesource.mqtt.client.MQTT;
import org.fusesource.mqtt.client.Message;
import org.fusesource.mqtt.client.QoS;
import org.fusesource.mqtt.client.Topic;

import java.net.URISyntaxException;


public class MainActivity extends AppCompatActivity implements View.OnClickListener,CompoundButton.OnCheckedChangeListener {

    final static String TAG = "MQTTClient";

    //UI
    ToggleButton    btnConnect;
    Button          btnPublish, btnSubscribe;
    EditText        edtServer,edtMessage,edtTopic,edtClientID;
    TextView        received;
    CheckBox        cbxPersist;

    //MQTT
    final static String clientId    = "android";
    final static short  keepAlive   = 255;
    final static String host        = "192.168.1.101";
    final static String user        = "guest";
    final static int    port        = 1883;
    final static String password    = "admin";

    MQTT                mqtt                ;
    Listener            listener            ;
    CallbackConnection  callbackConnection  ;
    Callback<Void>      connectCallback     ;
    Callback<byte[]>    subscribeCallback   ;
    Callback<Void>      publishCallback     ;
    Callback<Void>      disconnectCallback  ;

    {
        connectCallback = new Callback<Void>(){

            @Override
            public void onSuccess(Void value) {
                Log.d(TAG, "connectCallback : onSuccess");
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("connectCallback success");
                    }
                });

            }
            @Override
            public void onFailure(Throwable value) {
                value.printStackTrace();
                Log.d(TAG, "connectCallback : failure");
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("connectCallback failure");
                    }
                });
                System.exit(-2);
            }
        };
        disconnectCallback = new Callback<Void>(){

            public void onSuccess(Void value) {
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("disconnect success");
                    }
                });
            }
            public void onFailure(Throwable e) {
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("disconnect failure");
                    }
                });
            }
        };

        listener = new Listener() {

            @Override
            public void onConnected() {
                Log.d(TAG, "listener onConnected");
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("listener onConnected");
                    }
                });
            }

            @Override
            public void onDisconnected() {
                Log.d(TAG, "listener onDisconnected");
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("listener onDisconnected");
                    }
                });
            }

            @Override
            public void onPublish(final UTF8Buffer topic, Buffer msg, Runnable ack) {
                final String body = msg.utf8().toString();
                Log.d(TAG, "onPublish: " + body);
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        makeNotification(topic.toString(),body);
                        received.append("\nreceived : " + body);
                    }
                });
            }

            @Override
            public void onFailure(Throwable value) {
                Log.d(TAG, "listener failure");
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("listener failure");
                    }
                });
            }
        };

        subscribeCallback = new Callback<byte[]>() {

            public void onSuccess(byte[] qoses) {
                Log.d(TAG, "subscribe : success");

                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("subscribe " + edtTopic.getText().toString() + ": success");
                    }
                });
            }
            public void onFailure(Throwable value) {
                value.printStackTrace();
                Log.d(TAG, "subscribe : failure");
                received.post(new Runnable() {
                    @Override
                    public void run() {
                        received.setText("subscribe " + edtTopic.getText().toString() + ": failure");
                    }
                });
                System.exit(-2);
            }
        };
        publishCallback = new Callback<Void>() {
            @Override
            public void onSuccess(Void value) {
                Log.d(TAG, "onSuccess: ");
            }

            @Override
            public void onFailure(Throwable value) {
                Log.d(TAG, "onFailure: ");
            }
        };
    }

    void connect(){
        callbackConnection.connect(connectCallback);
    }

    void disconnect(){
        callbackConnection.disconnect(disconnectCallback);
    }

    void subscribe(){

        String topicName = edtTopic.getText().toString().trim();

        Topic topics[] = new Topic[]{new Topic(topicName,QoS.AT_LEAST_ONCE)};

        callbackConnection.subscribe(topics,subscribeCallback);

    }

    void publish(){

        String data = edtMessage.getText().toString();

        String topicName = edtTopic.getText().toString().trim();

        callbackConnection.publish(topicName,data.getBytes(),QoS.AT_LEAST_ONCE,false,publishCallback);

    }

    void initMqtt(){

        mqtt = new MQTT();
        try {
            mqtt.setHost(host, port);
            mqtt.setUserName(user);
            mqtt.setPassword(password);
            mqtt.setKeepAlive(keepAlive);
            mqtt.getClientId();
            callbackConnection = mqtt.callbackConnection();
            callbackConnection.listener(listener);

        } catch (URISyntaxException e) {
            e.printStackTrace();
            Log.e(TAG,"-=-=-=-=-=-=------------====\n initMqtt exception : " + e.getMessage());
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        received    = (TextView)    findViewById(R.id.txt_received);
        btnSubscribe= (Button)      findViewById(R.id.btn_subscribe);
        btnConnect  = (ToggleButton)findViewById(R.id.btn_connect);
        btnPublish  = (Button)      findViewById(R.id.btn_publish);
        edtServer   = (EditText)    findViewById(R.id.edt_server);
        edtTopic    = (EditText)    findViewById(R.id.edt_topic);
        edtMessage  = (EditText)    findViewById(R.id.edt_message);
        edtClientID = (EditText)    findViewById(R.id.edt_clientID);
        cbxPersist  = (CheckBox)    findViewById(R.id.cbx_persist);

        btnConnect  .setOnClickListener(this);
        btnConnect  .setOnCheckedChangeListener(this);
        cbxPersist  .setOnCheckedChangeListener(this);
        btnSubscribe.setOnClickListener(this);
        btnPublish  .setOnClickListener(this);

        initMqtt();

    }
    void makeNotification(final String title,final String content){

        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
        mBuilder.setSmallIcon(R.drawable.mail_3_small);//must
        mBuilder.setContentTitle(title);
        mBuilder.setContentText(content);
        // Creates an explicit intent for an Activity in your app
        Intent resultIntent = new Intent(this, MainActivity.class);

        // The stack builder object will contain an artificial back stack for the
        // started Activity.
        // This ensures that navigating backward from the Activity leads out of
        // your app to the Home screen.
        TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
        // Adds the back stack for the Intent (but not the Intent itself)
        stackBuilder.addParentStack(MainActivity.class);
        // Adds the Intent that starts the Activity to the top of the stack
        stackBuilder.addNextIntent(resultIntent);
        PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
        mBuilder.setContentIntent(resultPendingIntent);
        NotificationManager mNotificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // mNotificationId is a unique integer your app uses to identify the
        // notification. For example, to cancel the notification, you can pass its ID
        // number to NotificationManager.cancel().
        mNotificationManager.notify(R.string.app_name, mBuilder.build());
    }

    void blocking(){
        BlockingConnection connection = mqtt.blockingConnection();
        try {
            connection.connect();
            //publish
            connection.publish("foo", "Hello".getBytes(), QoS.AT_LEAST_ONCE, false);

            //subscribe
            Topic[] topics = {new Topic("foo", QoS.AT_LEAST_ONCE)};
            byte[] qoses = connection.subscribe(topics);

            //receive message
            Message message = connection.receive();
            System.out.println(message.getTopic());
            byte[] payload = message.getPayload();
            // process the message then:
            message.ack();

            //disconnect
            connection.disconnect();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){
            case R.id.btn_publish   :   publish();      break;
            case R.id.btn_subscribe :   subscribe();    break;
        }

    }

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
        switch (compoundButton.getId()){
            case R.id.btn_connect:
                if (!b){
                    connect();
                }else{
                    disconnect();
                }
                break;
            case R.id.cbx_persist:
                if (mqtt != null) {
                    mqtt.setClientId(edtClientID.getText().toString().trim());
                    mqtt.setCleanSession(!b);
                }
                break;
        }
    }

}
